#include "vfx_smoke.h"

#include "script/scripthelper.h"
#include "script/write_lua.h"
#include "math/intersection.h"
#include "graphics/graphics_util.h"

#include "num/rand.h"

#include "dd/dd_man.h"
#include "util/mmgr.h"		    // Needs to come in early
#include "util/common_macros.h"		// macros
#include "util/log.h"		    // logging
#include "util/timer.h"		    // logging
#include <cassert>
#include <math.h>
using namespace vfx;


Smoke::Smoke() :
	m_StartTime(0), 
	m_MaxTime(0),
	m_SizeMult(1),
	m_LastIndex(-1),
	m_ToRot(0), m_FromRot(0),
	m_ToRotSpeed(0), m_FromRotSpeed(0),
	m_Rebirth(-1),	// ignore
	m_MaxRotSpeed(30),
	m_FadeTimeMin(2), m_FadeTimeMax(4),
	m_IsDone(false)
{
	m_SetC = 5;
// initialize
	ResetPos();

}



Smoke::~Smoke()
{

}
void	Smoke::ResetPos() 
{
	m_MoveSpeed.x = num::RAND32::Instance().RandFloat(-0.05f, 0.05f);
}
void	Smoke::Tick(float dt)
{
	// update fog rotation
	m_ToRot += m_ToRotSpeed * dt;
	m_FromRot += m_FromRotSpeed * dt;

	// update fog drifting
	m_Pos += m_MoveSpeed * dt;
	m_SpriteFrom.Tick(dt);
	m_SpriteTo.Tick(dt);
	m_XFade.Tick(dt);

	if (m_XFade.IsReady())
	{
		m_XFade.Reset();
		SetupXFade();
	}
}

void	Smoke::SetupXFade()
{
	if (m_Rebirth == 0) // time to die
	{
		m_IsDone = (true);
		return;	// no more
	}
	num::RAND32&	rnd = num::RAND32::Instance();

	bool	CreateTo = true;
	if (m_Rebirth>0)
	{
		m_Rebirth--;
		if (m_Rebirth == 0)
			CreateTo = false;	// we're fading out in the next set
	}	
	m_SpriteTo.Create(m_SpriteFrom.GetFilename());
	m_ToRot = m_FromRot;
	m_ToRotSpeed = m_FromRotSpeed;

	if (CreateTo)
	{
		m_FromRot = rnd.RandFloat(0, 360);
		m_FromRotSpeed = rnd.RandFloat(-m_MaxRotSpeed, m_MaxRotSpeed);

		char	Buffer[64];
		int	Index = 1 + (rand() %m_SetC);
		if (Index == m_LastIndex) 
			Index = 1 + ((m_LastIndex + 1)%m_SetC);
		
		sprintf(Buffer, "effects/%s_%i.png", m_DataSet.c_str(), Index);
		
		m_SpriteFrom.Create(Buffer);
		m_SpriteFrom.GetScreenSize(m_BaseSize);
		m_Size = m_BaseSize;
		m_LastIndex = Index;
	} else
	{
		m_SpriteFrom.Invalidate();
	}
	

	m_XFade.SetLimit(	rnd.RandFloat(m_FadeTimeMin, m_FadeTimeMax));
}

void	Smoke::Render(const math::Vec2& Offset, float Scale)
{
	float		Prog = m_XFade.GetProgress();
	math::Vec2	Size = Scale * m_BaseSize* m_SizeMult;
	math::Vec2	Pos = (m_Pos + math::Vec2(0, -Size.y *0.4f) - Offset) * Scale;

	m_SpriteFrom.m_Color = ColorfRGBA(1,1,1,Prog);
	m_SpriteFrom.m_Size = Size;
	m_SpriteFrom.m_Pos = Pos;
	m_SpriteFrom.m_Rotation = m_FromRot;
	m_SpriteFrom.RenderRotated();
	
	m_SpriteTo.m_Color = ColorfRGBA(1,1,1,1.0f-Prog);
	m_SpriteTo.m_Size = Size;
	m_SpriteTo.m_Pos = Pos;
	m_SpriteTo.m_Rotation = m_ToRot;
	m_SpriteTo.RenderRotated();
}

void	Smoke::RenderDebug(const math::Vec2& Offset, float Scale)
{
}



///////////////////
SmokeGenerator::SmokeGenerator():
	m_NextCloud(0.4f),
	m_IterationC(5),
	m_ImgC(4)
{
	m_Base = "mist";
}

void	SmokeGenerator::Setup(float GenTime, int	MaxItr, const std::string& BaseName, int MaxImg)
{
	m_Base = BaseName;
	m_NextCloud.SetLimit(GenTime);
	m_IterationC = MaxItr;
	m_ImgC = MaxImg;
}

SmokeGenerator::~SmokeGenerator()
{

}

void SmokeGenerator::Tick(float dt)
{
	m_NextCloud.Tick(dt);
	if (m_NextCloud.IsReady())
	{
		m_NextCloud.Reset();
		Smoke* pFog = CreateSmoke();
		// setup the parameters here
		pFog->SetRebirthC(m_IterationC);
		pFog->SetSetC(m_ImgC);
		pFog->Init(m_Base);
		pFog->SetPos(m_Pos);
		m_Entries.push_back(pFog);
	}
	// tick through all
	for (int i=(int)(m_Entries.size())-1; i>=0; i--)
	{
		Smoke* pFog = m_Entries[i];
		pFog->Tick(dt);
		if (pFog->IsDone())
		{
			// reuse?
			delete pFog;
			m_Entries.erase(m_Entries.begin()+i);
		} 
	}
}

void	SmokeGenerator::Render(const math::Vec2& Offset, float Scale)
{
	for (int i=(int)(m_Entries.size())-1; i>=0; i--)
	{
		Smoke* pFog = m_Entries[i];
		pFog->Render(Offset, Scale);
	}
}